#ifndef EVICTION_LRU_HPP
#define EVICTION_LRU_HPP

#include "eviction/cache-eviction.hpp"
#include "utils/hash_queue.hpp"

/**
 * \file
 * \ingroup cacheEvict
 * cas::CacheEvictionLru declaration.
 */

namespace cas
{
    /**
     * \ingroup cacheEvict
     * LRU cache eviction algorithm
     */
    class CacheEvictionLru : public CacheEviction
    {
    public:
        /**
         * \brief Construct a new CacheEvictionLru object
         * \param [in] cacheSize maximum cache items, actual occupied memory of cache = \c cacheSize * 512B (logical block size)
         *     i.e. cacheSize: 16K -> 8M memory, 2M -> 1G
         */
        CacheEvictionLru(uint32_t cacheSize = 16384);
        virtual ~CacheEvictionLru();

        void reset() override;
        uint16_t lookup(const CacheRequest &request) override;
        void print() const; /**< print statistic */

        uint32_t getCacheSize() const override;
        void setCacheSize(uint32_t cacheSize) override;

        /**
         * \brief lru page structure
         */
        struct LruCachePage : CachePage
        {
            // LruCachePage *prev{nullptr}; /**< previous page */
            // LruCachePage *next{nullptr}; /**< next page */
            bool isPrefetch{false};    /**< if generated from prefetch */
            bool isPrefetchHit{false}; /**< if hit after prefetch */

            LruCachePage(uint16_t devno = 0u, uint64_t lba = 0u) : CachePage(devno, lba)
            {
                isPrefetch = isPrefetchHit = false;
            };

            friend inline bool operator==(const LruCachePage &lhs, const CachePage &rhs)
            {
                return lhs.devno == rhs.devno && lhs.lba == rhs.lba;
            }
            friend inline bool operator!=(const LruCachePage &lhs, const CachePage &rhs)
            {
                return !(lhs == rhs);
            }
            inline CachePage toCachePage() const;
        };

    private:
        typedef hash_queue<CachePage, LruCachePage> LruCachePool;
        LruCachePool pool;

        void push(CacheRequest request);
    };
} // namespace cas

#endif /* EVICTION_LRU_HPP */